package ws

import "my_go_open/utils"

func NewHub(fn, fu func(*Client), fb func(*Message) error) *Hub {
	hub := &Hub{
		Clients:    make(map[string]*Client),
		Broadcast:  make(chan *Message),
		Register:   make(chan *Client),
		Unregister: make(chan *Client),
	}
	go hub.run(fn, fu, fb)
	return hub
}

func (h *Hub) run(fn, fu func(*Client), fb func(*Message) error) {
	for {
		select {
		case client := <-h.Register:
			cid := client.Id
			if clientOld, ok := h.Clients[cid]; ok {
				cidOld := cid + "_old"
				clientOld.Id = cidOld
				h.Clients[cidOld] = clientOld
				_ = clientOld.Conn.Close()
			}
			h.Clients[cid] = client
			if fn != nil {
				go fn(client) // Register Callback
			}
		case client := <-h.Unregister:
			if _, ok := h.Clients[client.Id]; ok {
				delete(h.Clients, client.Id)
			}
			close(client.Send)
			if fu != nil {
				go fu(client) // Unregister Callback
			}
		case msg := <-h.Broadcast:
			if fb != nil && fb(msg) != nil { // Broadcast Callback
				continue
			}
			if len(msg.Recipients) > 0 && len(msg.Groups) == 0 { // 如果明确了接收者，减少循环次数
				for _, clientId := range msg.Recipients {
					if client, ok := h.Clients[clientId]; ok {
						select {
						case client.Send <- msg:
						default:
							h.Unregister <- client
						}
					}
				}
				continue
			}
			for _, client := range h.Clients {
				if client.Id == msg.Sender { // 不用发送给自己
					continue
				}
				bln := len(msg.Recipients) == 0 && len(msg.Groups) == 0 // 未明确接收者和接收组，发给全员
				if !bln && len(msg.Recipients) > 0 {
					bln, _ = utils.InArray(client.Id, msg.Recipients)
				}
				if !bln && len(client.Groups) > 0 && len(msg.Groups) > 0 {
					for _, group := range client.Groups {
						if bln, _ = utils.InArray(group, msg.Groups); bln {
							break
						}
					}
				}
				if !bln {
					continue
				}
				select {
				case client.Send <- msg:
				default:
					h.Unregister <- client
				}
			}
		}
	}
}
